#include "AnimationLoader.h"


/*
* Hip Center, Right & Left Foot are disabled! 31/3/2012 - MYY
*/

string skeletalNodeNames[SKELETAL_NODE_COUNT];

namespace AnimationLoader
{	
	//Hash table for Skeleton names to SkeletalNode enumeration
	map<string,SkeletalNodes> skeletalNodeMap;
	AnimationList* animList;
	string fileList[TOTAL_ANIMATION_FILES];


	Animation* AnimationCreator(const char* filename)
	{
		TiXmlDocument* doc = loadXMLFile(filename);
		Animation* animation = NULL;

		if(!doc) 
			return NULL;

		//Create Animation loaded from XML File
		animation = AnimationLoader::AnimationCreator(doc);	

		if(doc)
			delete doc;

		return animation;
	}

	TiXmlDocument* loadXMLFile(const char* filename) 
	{
		TiXmlDocument* doc = new TiXmlDocument(filename);
		bool loadOkay = doc->LoadFile();

		if (!loadOkay)
		{
			printf(doc->ErrorDesc());
			return NULL;
		} 
		else 
		{			
			return doc;
		}	
	}

	Animation* AnimationCreator(TiXmlDocument* animationFile)
	{
		Animation* newAnimation = NULL; 
		TiXmlHandle hDoc(animationFile);
		TiXmlElement* parentElem;
		TiXmlHandle hRoot(0);

		//Root Block -> Animation
		parentElem = hDoc.FirstChildElement().Element();

		//Does it have a valid root 
		if(!parentElem) 
			return newAnimation;

		PRINT_MESSAGE(parentElem->Value());
		// save this for later
		hRoot=TiXmlHandle(parentElem);

		newAnimation = new Animation;
	
		for (parentElem = hRoot.FirstChild().Element(); parentElem; parentElem->NextSibling() ? parentElem = parentElem->NextSibling()->ToElement() : parentElem = NULL)
		{
			newAnimation->addFrame(FrameCreator(parentElem));
		}
	
		return newAnimation;
	}

	Frame* FrameCreator(const TiXmlElement* parentElement)
	{
		Frame* newFrame = new Frame();
		//Get time value from XML
		const TiXmlElement* currentElement = parentElement->FirstChild()->ToElement();
		newFrame->setTime(stringToTime(currentElement->GetText()));

		//Travel to body
		currentElement = parentElement->FirstChild()->NextSibling()->FirstChild()->ToElement();
		Skeleton* newSkeleton = new Skeleton;

		//Iterate every node;
		for (currentElement; currentElement; currentElement->NextSibling() ? currentElement = currentElement->NextSibling()->ToElement() : currentElement = NULL)
		{	
			string name = currentElement->Attribute("name");		

			if(denyList(name))
				continue;

			Vector4f vec;

			//Position X
			const TiXmlElement* position = currentElement->FirstChild()->FirstChild()->ToElement();
			vec[0] = static_cast<float>(atof(position->GetText()));
			//Position Y
			position = position->NextSibling()->ToElement();
			vec[1] = static_cast<float>(atof(position->GetText()));
			//Position Z
			position = position->NextSibling()->ToElement();
			vec[2] =static_cast<float>(atof(position->GetText()));
			//Position W
			position = position->NextSibling()->ToElement();
			vec[3] = static_cast<float>(atof(position->GetText()));
		
			newSkeleton->addSkeletalNode(skeletalNodeMap[name], name.c_str(),vec);
		}

		newFrame->setSkeleton(newSkeleton);
		return newFrame;
	}

	//************************************
	// Method:    stringToTime
	// FullName:  stringToTime
	// Access:    public 
	// Returns:   long
	// Qualifier:
	// Parameter: const char * stringTime
	//
	// Assumption : No animation can be longer 
	//              than 1 minute.
	// x := milisecond
	// time format : hh:mm:ss.xxxxxxxxx
	//************************************
	long stringToTime(const char* stringTime)
	{
		long result = 0;
		unsigned int second, milisecond;
		string tempString = stringTime;

		second     = atoi(tempString.substr(6,2).c_str());
		milisecond = atoi(tempString.substr(9,3).c_str());

		result = second * 1000 + milisecond;
		return result;
	}

	AnimationList* Initialization()
	{
		//Skeletal Node map initialization
		//skeletalNodeMap["HipCenter"]		= nodeHipCenter;
		skeletalNodeMap["Spine"]			= nodeSpine;
		skeletalNodeMap["ShoulderCenter"]	= nodeShoulderCenter;
		skeletalNodeMap["Head"]				= nodeHead;
		skeletalNodeMap["ShoulderLeft"]		= nodeShoulderLeft;
		skeletalNodeMap["ElbowLeft"]		= nodeElbowLeft;
		skeletalNodeMap["WristLeft"]		= nodeWristLeft;
		skeletalNodeMap["HandLeft"]			= nodeHandLeft;
		skeletalNodeMap["ShoulderRight"]	= nodeShoulderRight;
		skeletalNodeMap["ElbowRight"]		= nodeElbowRight;
		skeletalNodeMap["WristRight"]		= nodeWristRight;
		skeletalNodeMap["HandRight"]		= nodeHandRight;
		skeletalNodeMap["HipLeft"]			= nodeHipLeft;
		skeletalNodeMap["KneeLeft"]			= nodeKneeLeft;
		skeletalNodeMap["AnkleLeft"]		= nodeAnkleLeft;
		//skeletalNodeMap["FootLeft"]			= nodeFootLeft;
		skeletalNodeMap["HipRight"]			= nodeHipRight;
		skeletalNodeMap["KneeRight"]		= nodeKneeRight;
		skeletalNodeMap["AnkleRight"]		= nodeAnkleRight;
		//skeletalNodeMap["FootRight"]		= nodeFootRight;

		//skeletalNodeNames[nodeHipCenter]		= "nodeHipCenter";
		skeletalNodeNames[nodeSpine]			= "Spine";
		skeletalNodeNames[nodeShoulderCenter]	= "ShoulderCenter";
		skeletalNodeNames[nodeHead]				= "Head";
		skeletalNodeNames[nodeShoulderLeft]		= "ShoulderLeft";
		skeletalNodeNames[nodeElbowLeft]		= "ElbowLeft";
		skeletalNodeNames[nodeWristLeft]		= "WristLeft";
		skeletalNodeNames[nodeHandLeft]			= "HandLeft";
		skeletalNodeNames[nodeShoulderRight]	= "ShoulderRight";
		skeletalNodeNames[nodeElbowRight]		= "ElbowRight";
		skeletalNodeNames[nodeWristRight]		= "WristRight";
		skeletalNodeNames[nodeHandRight]		= "HandRight";
		skeletalNodeNames[nodeHipLeft]			= "HipLeft";
		skeletalNodeNames[nodeKneeLeft]			= "KneeLeft";
		skeletalNodeNames[nodeAnkleLeft]		= "AnkleLeft";
		//skeletalNodeNames[nodeFootLeft]		= "FootLeft";
		skeletalNodeNames[nodeHipRight]			= "HipRight";
		skeletalNodeNames[nodeKneeRight]		= "KneeRight";
		skeletalNodeNames[nodeAnkleRight]		= "AnkleRight";
		//skeletalNodeNames["nodeFootRight"]	= "FootRight";

		//List of File Names
		fileList[0] = "hands_up.xml";
		fileList[1] = "hands_down.xml";
		fileList[2] = "left_up.xml";
		fileList[3] = "left_down.xml";
		fileList[4] = "right_up.xml";
		fileList[5] = "right_down.xml";

		//Allocation of Animation List
		animList = new AnimationList[TOTAL_ANIMATION_FILES];

		//Reading of animation files
		for (int i = 0; i < TOTAL_ANIMATION_FILES; i++)
		{
			animList[i] = AnimationCreator(fileList[i].c_str());
			animList[i]->setName(fileList[i].c_str());
		}

		return animList;
	}

	bool denyList(string name)
	{
		return ((name.compare("HipCenter") == 0) || 
				(name.compare("FootLeft") == 0)  || 
				(name.compare("FootRight") == 0));
	}

	bool denyList( SkeletalNodes index )
	{
		return (index == 0) ||   //HipCenter
			   (index == 15) ||  //FootLeft
			   (index == 19);	 //FootRight
	}
};